home *** CD-ROM | disk | FTP | other *** search
-
-
-
-
- FlexList II for ANSI C
-
-
- Copyright 1990
- John W. Small
- All rights reserved
-
- PSW / Power SoftWare
- P.O. Box 10072
- McLean, Virginia 22102 8072
- (703) 759-3838
-
- 10/4/90
-
-
-
- CLAIM TO PROPRIETARY TECHNIQUES
-
- Several features of FlexList used in combination make FlexList
- unique and versatile. The hybrid stack-queue-list-array data
- structure and the techniques used to implement it as a generic
- polymorphic object can be easily ported to other computer
- languages and remain intact in their essence. The author claims
- all rights to these features.
-
-
- SHAREWARE NOTICE
-
- This FlexList packet is offered to you as "shareware" meaning try
- before you buy. The shareware version allows you to test the
- product to see if it's suitable for your purposes. In order to
- legally use FlexList for any other purpose you must first license
- it from PSW / Power SoftWare by sending in a registration fee of
- $79.95. Upon registration you will receive a printed version of
- the complete manual (140+ pages) and both ANSI C and K&R source
- code.
-
-
- SHAREWARE MANUAL
-
- The shareware documentation that follows has been taken from the
- actual printed FlexList manual. I've include only the most vital
- information. Refer to flexlist.h for FlexList function
- prototypes. Flexlist.c contains comments that explain the
- virtual functions: FNnew, FNwrite, FNread, and FNdestruct.
-
-
-
-
-
- Introduction
-
-
- A FlexList is alot more than just a ready-to-run C linked list.
- It's a searchable-sortable-implodable generic heterogeneous-
- homogeneous hybrid stack-queue-list-array accessible by value,
- reference or node.
-
- Anytime your C application requires a stack, queue, or linked
- list, simply include flexlist.h in your source code and then
- start defining your stack, queue, and/or list variables as type
- FlexList. A FlexList can be initialized, by various constructor
- functions, to store any type of data and then accessed as a
- stack, queue, list, or even an array interchangeably!
-
- With more than 30 FlexList functions to choose from, you can
- push, pop, insert, delete, sort, store, recall, or find, to name
- but a few. Access your data by value (copy) or by reference
- (pointer). Or move nodes directly between FlexLists. Because
- FlexList functions adjust automatically to different types of
- data, new sets of primitives needn't be derived to accommodate
- new data types. Thus your application's coding time and code
- size won't continue to grow when you add new types of FlexLists.
- A FlexList can even be made to accommodate heterogeneous data via
- its virtual function hooks.
-
- With FlexList you can quickly construct lists of lists or other
- composite structures. And since FlexLists are initialized at run
- time, the data they hold or even their creation can be specified
- at run time thus allowing your application new dimensions of
- adaptability to user inputs.
-
- Use FlexList to code your next application's linked lists in
- minutes instead of days, without the usual debugging and
- documenting headaches associated with custom coding various list
- types. It's no problem modifying your application in midstream
- to incorporate various and differing list types; with FlexList no
- linked list code needs to be scrapped or rewritten. The code
- space you'll save over cloning list primitives for different data
- types may just save you from having to go the overlay/swapping
- route.
-
-
-
-
-
- Chapter 2. Programming with FlexList
-
-
- This chapter is a combination of a brief tutorial on using the
- FlexList tool and a logical survey of the FlexList functions.
- You may find it useful to lookup the FlexList functions in the
- reference chapter while reading the example programs here. Don't
- worry too much about the details for now. Instead you should
- finish this chapter with
-
- 1) an idea of the points to remember when programming with
- FlexList,
-
- 2) a conceptual model of FlexList's hybrid stack-queue-list-
- array data structure, and
-
- 3) an appreciation for the various ways that a FlexList can be
- manipulated and accessed, namely: by value, by reference, or
- by node.
-
- After programming for a while with FlexList, be sure to reread
- this chapter.
-
- Let's first cover several points that you should keep in mind
- when using FlexList in any application.
-
- 1. Include flexlist.h in any application using FlexList.
-
- #include <flexlist.h>
-
- 2. Define your stack, queue, or list as a FlexList.
-
- FlexList intStack;
-
- 3. Before using your FlexList you must call a constructor
- function to initialize it for the size of the data that you
- will be storing in it.
-
- FLfixed(&intStack,sizeof(int));
-
- 4. The address of your FlexList must be passed as the first
- parameter to FlexList functions. Where data copying is
- involved, the address of the data is passed as the second
- parameter. Remember, don't pass the data by value.
-
- for (i = 1; i < 11; i++)
- FLpushD(&intStack,&i); /* address of i */
-
-
-
-
-
- 5. FlexList functions return pointers or integers. A returned
- value of zero indicates failure of the function to carry out
- its task.
-
- while (FLpopD(&intStack,&i)) /* loop until false */
- printf("\n %d",i);
-
- 6. After you are finished with your FlexList you should call a
- FlexList destructor function. In our example it isn't
- really necessary since we've popped all the nodes anyway.
- Let's include it though for completeness.
-
- FLclear(&intStack);
-
- 7. Don't forget to link your application with the object module
- created by compiling flexlist.c or with the library you
- build.
-
- Let's see the whole program.
-
-
- #include <stdio.h> /* printf() */
- #include <flexlist.h>
-
- main() /* Count backwards from ten via a stack. */
- {
- FlexList intStack;
- int i;
-
- (void) FLfixed(&intStack,sizeof(int));
- for (i = 1; i < 11; i++)
- (void) FLpushD(&intStack,&i);
- while (FLpopD(&intStack,&i))
- (void) printf("\n %d",i);
- (void) FLclear(&intStack);
- return 0;
- }
-
-
- Dynamic FlexList Constructors
-
- Let's continue with a survey of FlexList's various functions.
- The FlexList tool has several constructor/destructor functions.
- Why? Well the FlexList that we just used in the previous example
- is a local variable. Actually only the FlexList header is a
- local variable - the nodes in a FlexList are almost always
- dynamically allocated! Suppose that we want the FlexList
- variable itself to be dynamically allocated? Then we would use
- the constructor function FLfixedNew.
-
-
-
-
-
- Let's see that program again.
-
- #include <stdio.h> /* printf() */
- #include <flexlist.h>
-
- main() /* Count backwards from ten via a stack. */
- {
- FlexL intS;
- int i;
-
- if ((intS = FLfixedNew(sizeof(int),0,FLDdestruct0))
- == FlexL0) return 1;
- for (i = 1; i < 11; i++)
- (void) FLpushD(intS,&i);
- while (FLpopD(intS,&i))
- (void) printf("\n %d",i);
- (void) FLdelete(&intS);
- return 0;
- }
-
- Notice that the integer stack is now defined as type FlexL
- instead of FlexList. FlexL is a pointer to a FlexList. I
- contracted intStack to intS also as a reminder that it is a
- pointer to a FlexList and not a FlexList. The constructor
- function FLfixedNew returns a pointer to the FlexList it
- allocates and initializes, otherwise it returns 0 or more
- specifically (FlexL) 0. I've contracted all NULL constants and
- defined them in flexlist.h, e.g. (FlexL) 0 is FlexL0. Several
- additional parameters are also required by FLfixedNew but don't
- worry about that now. Please note that FlexList primitives take
- a FlexList pointer as their first parameter, with the exception
- of FLdelete. That's why I didn't use the address of operator,
- "&", with "intS" in this version like I did with "&intStack" in
- the first.
-
- The point of the two previous examples is that FlexList
- constructor/destructor functions come in two varieties: those
- that construct/destruct FlexList variables defined at compile
- time, i.e. local, static, and global variables, versus their
- counter parts that construct/destruct FlexList variables
- dynamically allocated at run time.
-
-
-
-
-
- FlexList Constructor/Destructor Functions
-
- 1. Constructor/destructor functions for FlexLists defined at
- compile time:
-
-
- FLfixed() FLunpack() FLvariant()
- FLstr() FLclear()
-
-
- 2. Constructor/destructor functions for FlexLists allocated at
- run time:
-
-
- FLfixedNew() FLunpackNew() FLvariantNew()
- FLstrNew() FLdelete()
-
-
- The FLunpack and FLunpackNew functions are used to explode C
- arrays (vectors) into FlexLists. Each FlexNode holds one cell of
- the array (see section on compaction functions). FLvariant and
- FLvariantNew construct FlexLists that have variant sized
- FlexNodes (see FLvariant in reference chapter to see how to
- construct heterogeneous FlexLists)! FLstr and FLstrNew are
- actually macros that call FLvariant and FLvariantNew
- respectively, constructing FlexLists that contain FlexNodes just
- big be enough to hold C strings within. FLclear deallocates all
- FlexNodes in a FlexList, while FLdelete calls FLclear and then
- proceeds to deallocate the dynamically allocated FlexList
- variable (header).
-
-
- FlexList Header Access Functions
-
- As you become more familiar with what's inside a FlexList you
- will want to access the data fields inside the FlexList header.
- Never access these fields directly! There is little performance
- penalty since most of these functions are in fact macros. You
- should decide right now that you are only going to access the
- guts of a FlexList via FlexList functions. This insures the
- integrity of the FlexList by imposing the OOP (Object Oriented
- Programming) concept of encapsulation. The C language doesn't
- enforce access restriction as does the C++ language, so you're on
- the honor system!
-
-
-
-
-
- FLfrontD() FLcurrentD() FLrearD()
- FLcurNum() FLnodes() FLmaxNodes()
- FLsetMaxNodes() FLnotFull() FLsizeofNodeData()
- FLisSorted() FLunSort() FLcompare()
- FLsetCompare() FLisFixed() FLisVariant()
- FLData()
-
-
- A FlexList can be accessed as a stack, queue, list, or even an
- array once it has nodes in it, interchangeably. The FlexList
- header keeps track of everything so if your pushing data onto
- your "stack" at one moment, you can recall an element from your
- "array" the next. You can sort your FlexList, then perform
- various other operations on it and FLisSorted will tell you if it
- is still sorted. You can set an upper limit on the number of
- nodes a FlexList is allowed to hold with FLsetMaxNodes. You will
- come to know what each function does with time.
-
-
- FlexList Stack and Queue Functions
-
- A stack provides LIFO (Last In, First Out) storage. A complete
- set of stack primitives is provided. These functions don't
- disturb the queue, list, or array structure of a FlexList. In
- other words, you can access your FlexList as a stack at any time
- and revert back to accessing it as a queue, list, or array
- freely.
-
-
- FLpushN() FLpushD() FLpopN()
- FLpopD() FLtopD() FLinsQN()
- FLinsQD() FLfrontD() FLrearD()
-
-
- A queue provides FIFO (First In, First Out) storage. Notice that
- some of the stack functions double up here as queue functions,
- e.g. FLpopD, FLtopD. Also I have again included some of the
- FlexList header access functions, i.e. FLfrontD and FLrearD which
- return pointers to the data in the first and last nodes
- respectively. Basically I'm suggesting various logical ways to
- categorize FlexList functions to help you remember them. You'll
- find that several functions may belong in multiple categories.
-
- The functions ending with "N" work directly with the FlexNodes
- which contain your data. For an example, suppose that you want
- to pop your stack directly into your queue. The following code
- shows how.
-
- #include <stdio.h> /* printf() */
- #include <flexlist.h>
-
-
-
-
-
- FlexList s, q;
- int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
- int *iptr;
- #define inT0 ((int *)0)
-
- main() /* count to ten the hard way */
- {
- (void) FLunpack(&s,sizeof(a[0]),sizeof(a)/
- sizeof(a[0]),a);
- (void) FLfixed(&q,FLsizeofNodeData(&s));
- while ((iptr = FLinsQN(&q,FLpopN(&s))) != inT0)
- (void) printf("\n %d",*iptr);
- (void) FLclear(&s);
- (void) FLclear(&q);
- return 0;
- }
-
- In this example the stack is constructed by "exploding" an array
- of integers into a FlexList. Next the queue is constructed to
- hold the same size data as the stack. Then the stack is popped
- directly into the queue and a pointer to the data in the newly
- inserted queue node is captured and tested to control the
- looping! I print the integer each time so you can see that it
- made it into the queue. Did you notice how I defined the NULL
- integer pointer? I did that here so you'll know what's going on
- when you see other NULL pointers elsewhere.
-
-
- FlexList List Functions
-
- Any FlexList can be treated as a doubly linked list thereby
- providing sequential storage. You can insert nodes or delete
- them. The FlexList header maintains a current node pointer that
- lets the list functions know where the insertion or deletion is
- to take place. Stack and queue functions don't disturb this
- current pointer unless of course it points to the top/front of
- the stack/queue and that node is popped/removed. In that case
- the current node becomes undefined.
-
-
- FLmkcur() FLinsN() FLinsD()
- FLinsSortN() FLinsSortD() FLdelN()
- FLdelD() FLnextD() FLprevD()
- FLcurNum() FLcurrentD() FLcompare()
- FLsetCompare()
-
-
-
-
-
- FlexList nodes are numbered starting at one. When FLnextD
- reaches the end of the list the current node number is set to
- zero which is said to be undefined and FLnextD returns the NULL
- void pointer. On the next call to FLnextD the current node
- becomes one, that is of course if there are nodes in the
- FlexList! FLprevD works the same way. This mechanism makes it
- handy to walk around lists pausing at the ends. If you want to
- set the current pointer to a particular node, use FLmkcur.
-
- Oh, I guess I should mention again that you can store any type of
- data in a FlexList not just integers. Let's see something like
- that last example again with strings.
-
-
- #include <stdio.h> /* printf() */
- #include <flexlist.h>
-
- FlexList l;
- char *a[] = { "Now is the time", "for all good",
- "programmers to cut", "their coding time",
- "with FlexList!"
- };
- char **sptr;
- #define chaRR0 ((char **)0)
-
- main() /* PSW propaganda */
- {
-
- (void) FLunpack(&l,sizeof(a[0]),sizeof(a)/
- sizeof(a[0]),a);
- while ((sptr = FLnextD(&l,(void *)0)) != chaRR0)
- (void) printf("\n %s",*sptr);
- (void) FLmkcur(&l,FLnodes(&l));
- while (FLdelD(&l,(void *)0))
- /* null statement */; /* FLclear(&l); */
- (void) printf("\n There should be zero nodes now: %d",
- FLnodes(&l));
- return 0;
- }
-
-
- In this program I exploded a vector of char pointers into a
- FlexList. Whenever FlexLists are constructed the current node is
- set as undefined so FLnextD starts walking across the FlexList
- beginning with the first node. FLnextD will copy the data in the
- next node to whatever address you specify in the second parameter
- unless of course it is the NULL address! When you are browsing
- the reference chapter you will notice many FlexList functions
- that copy data to/from a FlexNode when an address is given. If
- the NULL address is specified the copying action is inhibited but
- the function otherwise performs its purpose. In this example
-
-
-
-
-
- FLnextD is inhibited from copying any data but it never the less
- moves the current pointer on to the next node. FLnextD also
- returns a void pointer to the data in the next node. I capture
- that pointer in order to print the string but I'm also using it
- to control the loop.
-
- All FlexList functions return either pointers or integer types
- that are non zero only when the respective function completes
- successfully. The void pointers returned from FlexList functions
- point to the user data in focus. In the case of FLnextD it
- points to the user data in the next node. I have simply type
- casted this pointer to a pointer to the type of data I'm storing
- in the FlexNodes in order to gain access to that data. As you
- can see FlexList functions allow you to access you data by value
- (copy) or by reference (pointer) as well as moving nodes directly
- between/within FlexLists.
-
- Back to our example, FLmkcur moves the current node pointer to
- the last node in the list. FLmkcur also returns a pointer to the
- data in the last node but I choose to ignore it. Now FLdelD is
- used to delete the nodes from the list. FLdelD removes the
- current node after copying its contents to the address specified
- (copying is inhibited here by the NULL address) and then unlinks
- the FlexNode from the FlexList and proceeds to deallocate it
- making the previous node in the FlexList the new current node. I
- might add that FLinsD does the exact opposite, i.e. inserts a new
- FlexNode after the current node making the new node current.
- Again the stack and queue structure of FlexList is undisturbed by
- any list functions invoked on the FlexList and vice versa.
-
-
- FlexList Search/Sort Functions
-
- The Search/Sort functions allow you to lookup and/or sort your
- data. Every FlexList has a user definable compare function. Use
- FLsetCompare to set a FlexList's internal compare function
- pointer. To facilitate sorting define your compare function to
- return -1, 0, or 1 to indicate whether the first data being
- compared is less than, equal to, or greater than the second,
- respectively. The compare function is also used for matching in
- the FLfind...() functions. Please note that most of the
- functions mentioned here modify the current node setting, thus
- they interact with the list functions mentioned earlier.
-
-
- FLinsSortN() FLinsSortD() FLfindFirstD()
- FLfindNextD() FLfindLastD() FLfindPrevD()
- FLsort() FLisSorted() FLunSort()
- FLcompare() FLsetCompare()
-
-
-
-
-
- Use FLinsSortD/N() to perform insertion sorts. If the list isn't
- sorted then FLsort will be called automatically before attempting
- the insertion. If a compare function pointer hasn't been setup
- then the insertion is aborted.
-
- The FLfind...D functions work regardless if the FlexList is
- sorted or not. If it is sorted then the binary search algorithm
- is used to find the first/last matching data and a linear search
- is used to find the next/previous match stopping immediately
- after the first mismatch. If the FlexList is not sorted then the
- linear search algorithm is used to find the first/last matching
- data and again to find the next/previous match stopping only at
- the ends of the list.
-
- Use FLsort or FLsetCompare to setup the compare function pointer.
- If the NULL compare function pointer, FLcompare0 (defined in
- flexlist.h), is passed to FLsort then the previous compare
- function pointer is used to sort the list. Call FLisSorted to
- determine whether a FlexList is still sorted from its last sort.
- For example, suppose you sort a list and pop some nodes off the
- front. Well that won't cause the FlexList to be unsorted so
- FLisSorted will return true. But if you push some data onto it
- treating it like a stack, that may or may not ruin the sorted
- order. FLisSorted will return false because it can no longer
- guarantee that the FlexList is sorted. You need to be careful
- though since FLnextD, FLprevD, and FLmkcur won't cause FLisSorted
- to reset to false even though you might have modified the data in
- the FlexNode via the returned void pointer! In that case you may
- want to call FLunSort to reset FLisSorted so that it will return
- false.
-
- The following example performs an unsorted linear search followed
- by an alphabetical sort.
-
-
- #include <stdio.h> /* printf() */
- #include <string.h> /* strstr(), strcmp() */
- #include <flexlist.h>
-
- int strStr(char *s, char *t)
- {
- return !(int)strstr(s,t);
- }
-
- main()
- {
- FlexList l;
- char *s, sbuf[80];
- char *mask = "overtime";
- int i;
-
-
-
-
-
- (void) FLstr(&l);
- (void) FLinsD(&l,"Once upon a time there were three");
- (void) FLinsD(&l,"programmers, who worked");
- (void) FLinsD(&l,"allot of overtime!");
- (void) FLinsQD(&l,"That was before the FlexList Fox");
- (void) FLinsQD(&l,"joined the staff!");
- for ((void)FLmkcur(&l,0); FLnextD(&l,sbuf);
- /* no reinit */)
- (void) printf("\n Node: %d. %s",
- FLcurNum(&l),sbuf);
- (void) FLsetCompare(&l,FLcomparE(strStr));
- if ((s = FLfindFirstD(&l,mask)) != (char *)0)
- (void) printf("\n Mask: \"%s\" found in \
- node: %d. %s",mask,FLcurNum(&l),s);
- (void) FLsort(&l,FLcomparE(strcmp));
- for (i = 1; FLrecallD(&l,sbuf,(unsigned)i); i++)
- (void) printf("\n Node: %d. %s",
- FLcurNum(&l),sbuf);
- (void) FLclear(&l);
- return 0;
- }
-
-
- This program constructs a variant FlexList via the macro
- constructor FLstr which expands into a call to FLvariant. The
- FlexNodes in this FlexList are only be enough to hold the
- character strings passed as parameters (please note that
- character string constants are pointers to the strings so I
- didn't use the address of, "&", operator!) I didn't use the
- FLunpack constructor because it builds fixed size FlexNode
- (homogeneous) FlexLists - an array has fixed cell sizes. Instead
- I inserted the strings one by one and queued the last two just to
- be different.
-
- The first "for loop" uses FLnextD to verify the contains of the
- FlexNodes. FLnextD only copies the string and zero terminator
- thanks to the virtual function table's function pointers (see
- FLvariant in the reference chapter to see how to construct
- heterogenous lists). Be sure that the variable whose address you
- pass to FLnextD is big enough to accommodate the largest data
- that can be read! You should have noticed that I had to use
- FLmkcur(&l,0) since the current node pointer is still pointing to
- the last node inserted and not the last node queued. Remember,
- queue functions don't disturb the list structure - the current
- node concept is part of the list structure, not the queue
- structure!
-
- Since the list is not sorted, FLfindFirstD searches in a linear
- fashion starting with the first node, internally calling the
- compare function setup with FLsetCompare. The FLcomparE macro,
- defined in flexlist.h, type casts strStr to the precise function
-
-
-
-
-
- pointer type required by both FLsetCompare and FLsort. My strStr
- returns 0 if t is within s. Since only a linear search will be
- used with this compare function, it doesn't matter that is
- doesn't return -1 or 1 to indicate less than or greater than.
-
- The program proceeds with a standard alphabetical sort and the
- resultant ordering is displayed with FLrecallD, an array access
- function which you'll see in the next section.
-
-
- FlexList Array Functions
-
- An array provides randomly accessible storage. A FlexList can
- also be accessed as an array once it has nodes in it.
-
-
- FLstoreD() FLrecallD() FLmkcur()
- FLcurrentD() FLcurNum()
-
-
- The last node accessed becomes the new current node. When
- randomly accessing a FlexList, FLmkcur is called internally by
- both FLstoreD and FLrecallD to make the requested node current.
- FLmkcur determines which pointer (front, current, or rear) is
- closest to the requested node. It then follows the FlexList's
- linkage from that closest pointer to the newly requested node.
- The current pointer is left positioned at the new node. Please
- note that array, search/sort, and list functions interact in that
- they all work with and modify the current node setting. Stack
- and queue functions are independent, however.
-
-
- FlexList Compaction Functions
-
- Sometimes you want to work with a list, other times it's more
- convenient to work with an array. Although FlexList allows this
- chameleon behavior, your application may progress in stages that
- favor a linked list at one point and a conventional C array at
- another. FlexList has "compaction" functions for converting a
- conventional array into a FlexList or vice versa, thus allowing
- you to optimize the performance of your application.
-
-
- FLunpack() FLunpackNew()
- FLpack() FLpackPtrs()
-
-
- You can think of the FLunpack/FLunpackNew as exploding the
- conventional C array into a FlexList. Think of the FLpack
- function as doing the exact opposite or imploding a FlexList into
- a conventional C array. Arrays compacted by FLpack and
- FLpackPtrs must be explicitly deleted with a call to free when no
-
-
-
-
-
- longer needed if their memory is ever to be recovered for
- subsequent reuse. FLpackPtrs returns an array of void pointers
- pointing to the data in the FlexNodes. This array is NULL
- terminated to facilitate subsequent processing.
-
- For the last example program we'll clone a vector of char
- pointers but the clone will have the advantage over its parent of
- being sorted in alphabetical order.
-
-
- #include <stdio.h> /* printf() */
- #include <stdlib.h> /* free() */
- #include <string.h> /* strcmp() */
- #include <flexlist.h>
-
- char *a[] = { "one", "two", "three", "four", "five" };
- char **A;
-
- int strCmp(char **s, char **t)
- {
- return strcmp(*s,*t);
- }
-
- main()
- {
- FlexList l;
- int i;
-
- (void) FLunpack(&l,sizeof(a[0]),sizeof(a)/
- sizeof(a[0]),a);
- (void) FLsort(&l,FLcomparE(strCmp));
- A = FLpack(&l);
- for (i = 0; i < sizeof(a)/sizeof(a[0]); i++)
- (void) printf("\n a[%d] = %s",i,a[i]);
- if (A) {
- for (i = 0; i < FLnodes(&l); i++)
- (void) printf("\n A[%d] = %s",
- i,((char **)A)[i]);
- free(A);
- }
- (void) FLclear(&l);
- return 0;
- }
-
- Remember that the FlexNodes in this program contain char pointers
- and that the compare function is passed pointers to the char
- pointers, that is why the strCmp has to dereference them.
-
- Many commercial C toolbox functions require vector parameters.
- With FlexList's compaction functions you can manipulate vectors
- on the fly. The vectors can be stored in files and loaded as
- needed via a FlexList and subsequent packing. The vector can
-
-
-
-
-
- then be kept around only during the computation phase in which it
- is needed. Large, oversized, static vectors need not be
- allocated at compile time to cope with worst case scenarios,
- thereby consuming precious data segment space within your
- program.
-
-
- Accessing FlexList Nodes and Data
-
- Now that we've finished categorizing FlexList functions along the
- lines of its hybrid stack-queue-list-array structure, let's
- rethink what we've seen in terms of how the FlexList was
- accessed, namely: by value, by reference, and by node. This
- gives us a second way to analyze FlexList functions.
-
- "By value" implies that the data is copied to or from a FlexNode.
- For example, with FLpopD the top node of the stack is popped and
- the data is copied to the address specified by the second
- parameter before the node is freed and returned to the heap. We
- are in effect accessing the data in the top node by value since
- we are retrieving, in actuality, a copy of it.
-
- FLpopD(&s,&i); /* i is same type in FlexNode */
-
- "By reference" implies that the data in the FlexNode is accessed
- by pointer. You will need to type cast these void pointers to
- pointers to the type of data you have stored in the FlexNodes.
- Suppose we're walking backward across a FlexList of integers with
- the code:
-
- while ((iptr = FLprevD(&l,(void *)0)) != (int *)0)
- (void) printf("\n %d",*iptr);
-
- All void pointers returned by FlexList functions point to user
- data. Thus the data can be modified directly. "By reference"
- functions are provided to speed up processing. Without pointer
- access you would have to first copy the data out of the FlexNode,
- modify it and then copy it back. With large data structures that
- could prove to be quite inefficient. Please note the FLnextD and
- FLprevD are purely "by reference" when called with their second
- parameters equal to the NULL address. Actually all FlexList
- functions returning void pointers allow access "by reference" in
- combination perhaps with "by value" access.
-
- In queuing network simulations you will want to move nodes
- between FlexLists rapidly. Without access "by node" you would
- have to "FLpopD" the source queue and "FLinsQD" the destination
- queue. This would entail copying the data from the front node
- into a local variable of the same type, unlinking and
- deallocating the FlexNode, then reallocating a new FlexNode and
- linking it into the other queue and finally copying the data from
- the local variable back into the node. The faster way is to
-
-
-
-
-
- unlink the FlexNode from the source queue and relink it directly
- into the destination queue, e.g.
-
- FLinsN(&dstQ,FLpopN(&srcQ));
-
- If dstQ is already full then the node popped from srcQ is lost in
- the twilight zone. A better approach would be to prevent the
- chance of FlexNodes being left dangling:
-
- while (FLnotFull(&dstQ) && FLnodes(&srcQ))
- (void) FLinsN(&dstQ,FLpopN(&srcQ));
-
- The "By node" functions unlink and relink FlexNodes directly
- between compatible FlexLists. Compatible in this sense means
- that both FlexLists have equal sizeofNodeData fields (not
- necessarily initialized for the same data type) . Use the
- FLsizeofNodeData function to read the sizeofNodeData field. Two
- FlexLists could also be considered to be compatible if they are
- both variant FlexLists with compatible data. I should point out
- that variant FlexLists have the sizeofNodeData fields set to
- zero. Be careful not to assume that two FlexLists are compatible
- just because both sizeofNodeData fields are equal to zero. You
- can use FLisVariant to retrieve the virtual function table
- pointer within the FlexList header. If two variant FlexLists use
- the same virtual function table, they are most likely compatible.
- You are responsible for insuring that your FlexLists are
- compatible. Remember also, FlexNodes unlinked with a function
- ending with "N" must be relinked with a function ending with "N"
- to a compatible FlexList or otherwise explicitly disposed of.
-
-
- Summary
-
- Let's review what we learned starting with the points to remember
- when programming with the FlexList tool.
-
- 1. Be sure to include the FlexList header in any module
- that references FlexList functions.
-
- 2. Define your global, static, and local stacks, queues,
- lists, etc. as "FlexList". Define your dynamic
- versions as pointers to FlexLists, i.e. "FlexL".
-
- 3. Construct your FlexList variable with a static
- constructor function and your FlexList pointer with a
- dynamic constructor function.
-
-
-
-
-
- 4. The first parameter of all FlexList functions, with the
- exception of FLdelete, is an address of a FlexList, or
- putting it another way, is a pointer to a FlexList. If
- the function is somehow involved with the copying of
- user data, the address of the data is always passed in
- the second parameter.
-
- 5. All FlexList functions return either pointers or
- integers. A returned value of zero indicates failure
- of the function to complete its task.
-
- 6. Destruct all FlexLists when they are no longer needed.
- Use FLclear on global, static, or local FlexList
- variables and FLdelete on dynamic FlexLists.
-
- 7. Link your application with the compiled flexlist object
- module or the flexlist library you build.
-
-
- Next, let's review the various functions available in the
- FlexList tool. FlexList functions can be categorized according
- to the logical nature of a FlexList's inherent hybrid stack-
- queue-list-array structure.
-
-
- FlexList Constructor/Destructor Functions
-
- FLfixed() FLunpack() FLvariant()
- FLstr() FLclear()
-
- FLfixedNew() FLunpackNew() FLvariantNew()
- FLstrNew() FLdelete()
-
-
- FlexList Header Access Functions
-
- FLfrontD() FLcurrentD() FLrearD()
- FLcurNum() FLnodes() FLmaxNodes()
- FLsetMaxNodes() FLnotFull() FLsizeofNodeData()
- FLisSorted() FLunSort() FLcompare()
- FLsetCompare() FLisFixed() FLisVariant()
- FLData()
-
-
- FlexList Stack and Queue Functions
-
-
- FLpushN() FLpushD() FLpopN()
- FLpopD() FLtopD() FLinsQN()
- FLinsQD() FLfrontD() FLrearD()
-
-
-
-
-
- FlexList List Functions
-
- FLmkcur() FLinsN() FLinsD()
- FLinsSortN() FLinsSortD() FLdelN()
- FLdelD() FLnextD() FLprevD()
- FLcurNum() FLcurrentD() FLcompare()
- FLsetCompare()
-
-
- FlexList Search/Sort Functions
-
- FLinsSortN() FLinsSortD() FLfindFirstD()
- FLfindNextD() FLfindLastD() FLfindPrevD()
- FLsort() FLisSorted() FLunSort()
- FLcompare() FLsetCompare()
-
-
- FlexList Array Functions
-
- FLstoreD() FLrecallD() FLmkcur()
- FLcurrentD() FLcurNum()
-
-
- FlexList Compaction Functions
-
- FLunpack() FLunpackNew() FLpack()
- FLpackPtrs()
-
-
- Finally, FlexLists can be accessed "by value", "by reference",
- and "by node." "By value" entails the copying of user data
- between the FlexNodes and user specified addresses. If the
- address specified is NULL than the copying of data is inhibited
- but the function performs otherwise as expected. The address is
- always the second parameter of the FlexList function requiring
- it. "By reference" infers that user data is manipulated directly
- inside a FlexNode via a pointer. All FlexList functions
- returning void pointers allow "by reference" access. "By node"
- functions allow FlexNodes to be yanked/inserted from/into
- FlexLists. These functions are named with "N" suffixes. Move
- FlexNodes only between compatible FlexLists. Don't leave
- FlexNodes dangling: either insert them back into a compatible
- FlexList with an "N" function or explicitly free them.
-
-
- By now you should be ready to start the planning and subsequent
- coding of your FlexList application with the help of the
- reference chapter on FlexList functions. Later, when you feel
- comfortable with FlexList, you will want to try your hand at
- deriving your own variant FlexLists (lists that contain
-
-
-
-
-
- heterogeneous data). Be sure to read the entry for FLvariant in
- the reference chapter for an explanation of writing your own
- FlexList virtual functions that accommodate your heterogeneous
- data. The FlexList dynamic constructor entries, i.e. constructor
- functions ending with "New", explain how to encapsulate your
- list-pertinent data within FlexList headers.
-